﻿using Abp.BackgroundJobs;
using Abp.Dependency;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Mt.Site.Core.Base.Domain.Entities;
using Mt.Site.Core.ContentManagement.Entities;
using Mt.Site.Core.Navigations;
using Mt.Site.Core.Navigations.Entities;
using Mt.Site.Core.Storage;
using Mt.Site.Core.Synchronization;
using Mt.Site.Core.Synchronization.ContentManagement;
using Mt.Site.Core.Synchronization.Data;
using Mt.Site.Core.Synchronization.Storage;
using System;
using System.Threading.Tasks;

namespace Mt.Site.Core.BackGroundJobs.Storage
{
    public class SynchorizationFileObjectJob: AsyncBackgroundJob<BaseAndMenuIdArgs>, ITransientDependency
    {
        private readonly IFileObjectAutoSyncManager _fileObjectAutoSyncManager;

        private readonly IBackgroundJobManager _backgroundJobManager;

        private readonly ISynchronizationHelper _synchronizationHelper;

        private readonly IRepository<FileObject, Guid> _fileObjectRepository;

        private readonly IIocResolver _iocResolver;

        private readonly IUnitOfWorkManager _unitOfWorkManager;

        public SynchorizationFileObjectJob(
                IFileObjectAutoSyncManager fileObjectAutoSyncManager,
                IBackgroundJobManager backgroundJobManager,
                ISynchronizationHelper synchronizationHelper,
                IRepository<FileObject, Guid> fileObjectRepository,
                IIocResolver iocResolver,
                IUnitOfWorkManager unitOfWorkManager)
        {
            _fileObjectAutoSyncManager = fileObjectAutoSyncManager;
            _backgroundJobManager = backgroundJobManager;
            _synchronizationHelper = synchronizationHelper;
            _fileObjectRepository = fileObjectRepository;
            _iocResolver = iocResolver;
            _unitOfWorkManager = unitOfWorkManager;
        }

        [UnitOfWork]
        public override async Task ExecuteAsync(BaseAndMenuIdArgs args)
        {
            using (_unitOfWorkManager.Current.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var fromObject = _fileObjectRepository.FirstOrDefault(args.Id);
                if (fromObject == null)
                {
                    return;
                }
                var entity = _synchronizationHelper.FindContentTypeByContentGuid(fromObject.ContentId, fromObject.TenantId);
                if (entity != null)
                {
                    long menuId = 0;
                    if (entity as Menu != null)
                    {
                        menuId = (entity as INeedAuxiliaryId).AuxiliaryId;
                    }
                    else
                    {
                        menuId = (entity as IMenuId).MenuId;
                    }

                    if (menuId == 0)
                    {
                        return;
                    }

                    if (args.OperateType == OptionType.Create || args.OperateType == OptionType.Update)
                    {
                        await CreateOrUpdateFileObject(menuId, entity, args, fromObject.ContentId);
                    }
                    else if (args.OperateType == OptionType.Delete)
                    {
                        await DeleteFileObject(menuId, entity, args, fromObject.ContentId);
                    }
                }
            }
               
        }


        private async Task CreateOrUpdateFileObject(long menuId, Entity<Guid> entity, BaseAndMenuIdArgs args,Guid fromCotnentId)
        {
            var notify = new NoticeArgs();
            notify.Type = args.OperateType;
            using (var scope = _iocResolver.CreateScope())
            {
                var sonSites = _synchronizationHelper.GetSonSite(args.FromTenantId, args.FromLanguage, menuId);
                foreach (var item in sonSites)
                {
                    try
                    {
                        AutoSyncInfoStore syncInfo = new AutoSyncInfoStore();
                        var isMenuEntity = false;
                        var toFileObjectId = Guid.Empty;
                        if (!item.AutoSynchronous)
                        {
                            continue;
                        }

                        if (entity as Menu != null)
                        {
                            var menuSync = scope.Resolve<IRepository<Menu, Guid>>();
                            var toMenuEntry = menuSync.FirstOrDefault(n => n.AuxiliaryId == menuId && n.TenantId == item.TargetTenantId);
                            if (toMenuEntry == null)
                            {
                                continue;
                            }
                            syncInfo.ToId = toMenuEntry.Id;
                            syncInfo.IsAutoSync = true;
                            isMenuEntity = true;
                        }
                        else
                        {
                            GetEntityAutoSyncInfo(scope, syncInfo, entity, item.TargetTenantId, item.TargetLanguage, fromCotnentId, notify, true);
                        }


                        if (syncInfo.ToId == Guid.Empty)
                        {
                            continue;
                        }

                        if (!isMenuEntity)
                        {
                            toFileObjectId = _fileObjectAutoSyncManager.CreateOrUpdateFileObjectAutoSync(
                                    new CreateOrUpdateSynchorizeStore
                                    {
                                        Id = args.Id,
                                        OptionType = args.OperateType,
                                        TargetLanguage = item.TargetLanguage,
                                        ToTenantId = item.TargetTenantId
                                    }, syncInfo.ToId);
                            if (toFileObjectId != Guid.Empty)
                            {
                                await _synchronizationHelper.SendNoticeForSuccessAsync(notify);
                            }
                        }
                        else
                        {
                            toFileObjectId = await _fileObjectAutoSyncManager.CreateOrUpdateFileObjectByMenuSync(
                                    new CreateOrUpdateSynchorizeStore
                                    {
                                        Id = args.Id,
                                        OptionType = args.OperateType,
                                        TargetLanguage = item.TargetLanguage,
                                        ToTenantId = item.TargetTenantId
                                    }, syncInfo.ToId, menuId);
                        }


                        if (toFileObjectId != Guid.Empty)
                        {
                            var nextSons = _synchronizationHelper.GetSonSite(item.TargetTenantId, item.TargetLanguage, menuId);

                            if (nextSons.Count > 0)
                            {
                                _backgroundJobManager.Enqueue<SynchorizationFileObjectJob, BaseAndMenuIdArgs>(
                                    new BaseAndMenuIdArgs
                                    {
                                        FromLanguage = item.TargetLanguage,
                                        FromTenantId = item.TargetTenantId,
                                        Id = toFileObjectId,
                                        MenuId = menuId,
                                        OperateType = args.OperateType
                                    });
                            }
                        }
                    }
                    catch (Exception)
                    {
                        if (notify.FromId != Guid.Empty)
                        {
                            await _synchronizationHelper.SendNoticeForFailAsync(notify);
                        }
                        throw;
                    }
                }
            }
        }

        private async Task DeleteFileObject(long menuId, Entity<Guid> entity, BaseAndMenuIdArgs args, Guid fromCotnentId)
        {
            var notify = new NoticeArgs();
            notify.Type = args.OperateType;
            using (var scope = _iocResolver.CreateScope())
            {
                var sonSites = _synchronizationHelper.GetSonSite(args.FromTenantId, args.FromLanguage, menuId);
                try
                {
                    foreach (var item in sonSites)
                    {
                        AutoSyncInfoStore syncInfo = new AutoSyncInfoStore();
                        var isMenuSync = false;
                        var toFileId = Guid.Empty;
                        if (!item.AutoSynchronous)
                        {
                            continue;
                        }

                        if (entity as Menu != null)
                        {
                            isMenuSync = true;
                        }
                        else
                        {
                            GetEntityAutoSyncInfo(scope, syncInfo, entity, item.TargetTenantId, item.TargetLanguage, fromCotnentId, notify);
                        }
                        

                        if (!isMenuSync)
                        {
                            if (syncInfo.ToId == Guid.Empty)
                            {
                                continue;
                            }
                            toFileId = _fileObjectAutoSyncManager.DeleteFileObjectSync(
                                new DeleteSyncStore
                                {
                                    Id = args.Id,
                                    OptionType = args.OperateType,
                                    TargetLanguage = item.TargetLanguage,
                                    ToTenantId = item.TargetTenantId
                                });
                            if (toFileId != Guid.Empty)
                            {

                                await _synchronizationHelper.SendNoticeForSuccessAsync(notify);
                            }
                        }
                        else
                        {
                            toFileId = await _fileObjectAutoSyncManager.DeleteFileObjectByMenuSync(
                                    new DeleteSyncStore
                                    {
                                        Id = args.Id,
                                        OptionType = args.OperateType,
                                        TargetLanguage = item.TargetLanguage,
                                        ToTenantId = item.TargetTenantId
                                    }, menuId);
                        }


                        if (toFileId != Guid.Empty)
                        {
                            var nextSons = _synchronizationHelper.GetSonSite(item.TargetTenantId, item.TargetLanguage, menuId);
                            if (nextSons.Count > 0)
                            {
                                _backgroundJobManager.Enqueue<SynchorizationFileObjectJob, BaseAndMenuIdArgs>(
                                            new BaseAndMenuIdArgs
                                            {
                                                FromLanguage = item.TargetLanguage,
                                                FromTenantId = item.TargetTenantId,
                                                Id = toFileId,
                                                MenuId = menuId,
                                                OperateType = args.OperateType
                                            });
                            }
                        }
                    }
                }
                catch (Exception)
                {
                    if (notify.FromId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForFailAsync(notify);
                    }
                    throw;
                }
            }
        }


        private void GetEntityAutoSyncInfo(IScopedIocResolver scope, AutoSyncInfoStore syncInfo, Entity<Guid> entity, int targetTenantId, string targetLanguage, Guid fromCotnentId, NoticeArgs notify,bool isRequireSync = false)
        {
            AutoSyncInfoStore autoSyncInfo = null;
            if (entity as Content != null)
            {
                var contentAutoSync = scope.Resolve<IContentAutoSyncManager>();
                autoSyncInfo = contentAutoSync.CheckContentAndAutoSyncInfo(targetTenantId, targetLanguage, fromCotnentId, notify, isRequireSync);
            }

            if (autoSyncInfo == null || autoSyncInfo.ToId == Guid.Empty)
            {
                syncInfo.ToId = Guid.Empty;
                return;
            }

            syncInfo.ToId = autoSyncInfo.ToId;
            syncInfo.IsAutoSync = autoSyncInfo.IsAutoSync;
        }
    }
}
